Async Generatorを外部から中断する
中断したいときにbreakやthrowをfor await...of中で呼べば、Async Generator内のfinally句に飛ぶことができるらしいhttps://zenn.dev/qnighy/articles/112af47edfda96#returnとthrowが呼ばれるタイミング
これを用いれば、複数回値を返すEvent ListenerをPromiseに変換する事ができる
/miyamonz/async awaitで何かを待つような処理を同期的に書くの拡張版
例:10回だけ#text-inputのeventを取得するscript
code:test-exec.js
import {listenInput} from "./test.js";
(async () => {
let count = 0;
for await (const event of listenInput()) {
count++;
if (count > 10) break;
console.log(event);
}
})();
code:test.js
const textInput = document.getElementById("text-input");
function getPromise() {
let _resolve;
const update = () => new Promise((res) => _resolve = res);
const resolve = (value) => _resolve?.(value);
return update, resolve;
}
export async function* listenInput() {
const waitEventFired, resolve = getPromise();
const callback = e => resolve(e);
textInput.addEventListener("input", callback);
try {
console.log("Start iteration"); // for debug
while (true) {
yield await waitEventFired();
}
} finally {
// 後始末
console.log("End iteration"); // for debug
textInput.removeEventListener("input", callback);
}
}
この書き方は/miyamonz/async awaitで何かを待つような処理を同期的に書くからの連想で思いついた
Async Generatorを使えば何回も呼ばれるcallbackをpromisifyできるんじゃないか、というアイデアは少し前から考えていて、今日ふと試してみた
他にもこのやり方をやっている人がいるかは調べていないみた
そこそこ見つかった
Simplest Async | Going Async With ES6 Generators
via javascript - How can I convert this async callback to a generator? - Stack Overflow
ていうかNode.jsの標準ライブラリにあるんかい!
https://zenn.dev/qnighy/articles/772f632af595aa#promiseへの変換
node:events.once()
https://github.com/denoland/deno_std/blob/0.126.0/node/_events.js#L818-L868
node:events.on()
https://github.com/denoland/deno_std/blob/0.126.0/node/_events.js#L906-L1037
for awaitループを処理している間に発火したeventは全て捨てられる
次のループに入るまで、resolveが更新されない
更新前、つまり解決済みのPromiseのresolveを何度呼び出してもなにも起きない
eventを捨てないパターンも作りたいなtakker.icon
これらはasync-libで実装した
2021-10-13
15:21:52 函数をundefinedで呼び出す可能性のある部分が合ったので修正
10:59:26 名前変更
s/update/waitEventFired
10:57:29 ↓で問題なさそうだったので直した
10:53:25 最初のeventがundefinedになってしまう/villagepump/@miyamonz#6163d889385a9200003dea46
指摘されたとおり、↓でいいのでは?
code:diff
while (true) {
- const event = await done;
- done = update();
- yield event;
+ yield await update();
}
なんでこうしなかったんだっけ?takker.icon
update()を待ってもすぐにresolveしないから?
いやいやそれでいいんだよtakker.icon
event listenerが発火するまで待つんだから
Related to
非同期のジェネレータの反復処理 | for await...of - JavaScript | MDN
#2022-06-12 09:03:16
#2021-10-24 23:58:25
#2021-10-13 10:56:45
#2021-10-10 09:42:20